package com.auto.api.core.service.impl;

import com.auto.api.core.builder.RequestMappingInfoBuilder;
import com.auto.api.core.entity.ApiInfo;
import com.auto.api.core.service.ApiStoreService;
import com.auto.api.core.util.SpringContextHolder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

/**
 * @program:
 * @description: 加载封装 ApiInfo
 * @author: liangshf
 * @create: 2022-01-07
 */
@Component
public class ApiStoreServiceImpl implements ApiStoreService {

    protected final Logger logger = LoggerFactory.getLogger(getClass());
    public static final String REQUEST_MAPPING_HANDLER_MAPPING = "requestMappingHandlerMapping";
    public static final String SWAGGER = "swagger";
    public static final String BASIC_ERROR_CONTROLLER = "BasicErrorController";
    public static final String HEALTH_CHECK_CONTROLLER = "HealthCheckController";
    public static final String PREFIX = "[";
    public static final String SUFFIX = "]";
    public final static ParameterNameDiscoverer parameterUtil;

    static {
        parameterUtil = new LocalVariableTableParameterNameDiscoverer();
    }

    /**
     * 从spring容器中加载封装 ApiInfo
     */
    public List<ApiInfo> scanApiList() {
        ApplicationContext applicationContext = SpringContextHolder.getApplicationContext();
        Assert.notNull(applicationContext);
        // 请求url和处理方法的映射
        List<ApiInfo> apiInfoList = new ArrayList();
        RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext
            .getBean(REQUEST_MAPPING_HANDLER_MAPPING);
        Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping
            .getHandlerMethods();

        for (Map.Entry<RequestMappingInfo, HandlerMethod> m : map.entrySet()) {
            String controllerName = getControllerName(m.getValue());
            if (filterController(controllerName)) {
                continue;
            }
            RequestMappingInfoBuilder build = new RequestMappingInfoBuilder();
            RequestMappingInfoBuilder.Builder builder = build.instance(
                getRequestUrl(m.getKey().getPatternsCondition())
                , getRequestType(m.getKey().getMethodsCondition().toString())
                , controllerName
                , m.getValue().getMethod()
                , parameterUtil
            );
            apiInfoList.add(builder.buildCommon().build());
        }
        return apiInfoList;
    }

    private String getRequestType(String methodCondition) {
        String requestType = methodCondition;
        if (StringUtils.isEmpty(requestType)) {
            return HttpMethod.POST.name();
        }
        if (requestType != null && requestType.startsWith(PREFIX) && requestType.endsWith(SUFFIX)) {
            requestType = requestType.substring(1, requestType.length() - 1);
        }
        if (StringUtils.isEmpty(requestType)) {
            return HttpMethod.POST.name();
        }
        return requestType;
    }

    private String getRequestUrl(PatternsRequestCondition patternsCondition) {
        return patternsCondition.getPatterns().stream().findFirst().get();
    }

    private String getControllerName(HandlerMethod mappingInfoValue) {
        return mappingInfoValue.getBeanType().getName();
    }

    private boolean filterController(String controllerName) {
        return controllerName.indexOf(SWAGGER) != -1
            || controllerName.indexOf(BASIC_ERROR_CONTROLLER) != -1
            || controllerName.indexOf(HEALTH_CHECK_CONTROLLER) != -1;
    }

}
